package org.bozo.im.service.protocols.xmpp.stanza.task.sasl;

import java.security.MessageDigest;

import org.bozo.im.service.protocols.xmpp.XMPPSession;
import org.bozo.im.service.protocols.xmpp.stanza.task.Task;
import org.bozo.im.service.protocols.xmpp.util.encoding.Base64;
import org.bozo.im.service.protocols.xmpp.util.encoding.Hex;
import org.bozo.im.service.protocols.xmpp.util.namespace.Namespace;

public class MD5ChallengeTask extends Task {

	private String mRealm;
	private String mNonce;
	private String mQop;
	
	public MD5ChallengeTask(String pId, String pRealm, String pNonce, String pQop) {
		super(pId);
		mNonce = pNonce;
		mRealm = pRealm;
		mQop = pQop;
	}

	@Override
	public void doTask(XMPPSession pSession, StringBuilder pBuilder) throws Exception {
		pBuilder.append("<response xmlns='").append(Namespace.SASL.getNamespace()).append("'>");

		String lLoginName = pSession.getConfiguration().getLoginJID().getNode();
		String lRealm = mRealm;
		String lPassword = pSession.getConfiguration().getPassword();
		String lNonce = mNonce;
		String lConce = (String)pSession.getConfiguration().getProperty("md5-conce");
		String lDigestUri = "xmpp/" + pSession.getConfiguration().getLoginJID().getDomain();
		int lNcInt = (Integer)pSession.getConfiguration().getProperty("md5-nc");
		
		String lNc = Integer.toHexString(lNcInt);
		
		while (lNc.length() < 8)
			lNc = "0" + lNc;
		
		StringBuilder lResponse = new StringBuilder();
		lResponse.append("username=\"").append(lLoginName).append("\",");
		lResponse.append("realm=\"").append(lRealm).append("\",");
		lResponse.append("nonce=\"").append(lNonce).append("\",");
		lResponse.append("conce=\"").append(lConce).append("\",");
		lResponse.append("nc=").append(lNc).append(",");
		lResponse.append("qop=").append(mQop).append(",");
		lResponse.append("digest-uri=\"").append(lDigestUri).append("\",");
		
		String A1;
		String A2 = "AUTHENTICATE:" + lDigestUri;

		StringBuilder lBuilder = new StringBuilder();
		lBuilder.append(lLoginName).append(':').append(lRealm).append(':').append(lPassword).append(':').append(lNonce).append(':').append(lConce);

		MessageDigest lMD5Digest = MessageDigest.getInstance("MD5");
		lMD5Digest.update(lBuilder.toString().getBytes());
		byte[] A1Bytes = lMD5Digest.digest();

		lMD5Digest = MessageDigest.getInstance("MD5");
		lMD5Digest.update(A1Bytes);
		A1Bytes = lMD5Digest.digest();
		
		lMD5Digest = MessageDigest.getInstance("MD5");
		lMD5Digest.update(A2.getBytes());
		byte[] A2Bytes = lMD5Digest.digest();
		
		A1 = Hex.encode(A1Bytes);
		A2 = Hex.encode(A2Bytes);
		
		lBuilder = new StringBuilder();
		
		A2 = lBuilder.append(lNonce).append(':').append(lNc).append(':').append(lConce).append(':').append(mQop).append(':').append(A2).toString();

		lBuilder = new StringBuilder();
		
		String lCredentials = lBuilder.append(A1).append(':').append(A2).toString();

		lMD5Digest = MessageDigest.getInstance("MD5");
		lMD5Digest.update(lCredentials.getBytes());
		byte[] lCredentialsBytes = lMD5Digest.digest();
		lCredentials = Hex.encode(lCredentialsBytes).toLowerCase();

		lResponse.append("response=").append(lCredentials).append(',');
		lResponse.append("charset=utf-8");
		
		String lContent = Base64.encode(lResponse.toString());

		pBuilder.append(lContent);
		pBuilder.append("</challenge>");
		
		pSession.getConfiguration().putProperty("md5-nc", lNc+1);
	}

}
